package com.wits.demoosd;

import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

import com.wits.media.ColorConvert;
import com.wits.media.Rgb;
import com.wits.media.YuvBlit;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;


public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        checkCameraPermission();

        onClickDemo(null);
    }

    public void onClickDemo(View view) {
        //demoYuv();

//        demoLoad();

        demoMixer();
    }

    public void demoMixer() {
//        String name = "src.jpg";
//        String filepath = makePath(name);
//        Bitmap srcBitmap = loadBitmap(filepath);
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.outWidth = 640;
        options.outHeight = 480;
        Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.src, options);
        if (srcBitmap == null) {
            return;
        }

        byte[] videoYuv = getYV12(srcBitmap);

        float textSize = 24.0f;
        Bitmap textBitmap = textAsBitmap("好贵啊", textSize, Color.argb(255, 0, 255, 0));
        byte[] textYuv = getYV12(textBitmap);

        {
            String name = formatName(textBitmap, "text", ".yv12");
            String filepath = makePath(name);
            saveData(textYuv, filepath);
        }

        render(videoYuv, srcBitmap.getWidth(), srcBitmap.getHeight(),
                textYuv, textBitmap.getWidth(), textBitmap.getHeight(), 100, 50);
        String outName = formatName(srcBitmap, "out", ".yv12");
        String filepath = makePath(outName);

        saveData(videoYuv, filepath);

    }

    public void render(byte[] video, int videoWidth, int videoHeight, byte[] mask, int maskWidth, int maskHeight, int x, int y) {
        YuvBlit.Plane videoPlane = new YuvBlit.Plane(video, 0, videoWidth, videoHeight, videoWidth);
        YuvBlit.YuvPlanes videoPlanes = YuvBlit.YuvPlanes.clipYV12(videoPlane, x, y, maskWidth, maskHeight);

        YuvBlit.Plane maskPlane = new YuvBlit.Plane(mask, 0, maskWidth, maskHeight, maskWidth);
        YuvBlit.YuvPlanes maskPlanes = YuvBlit.YuvPlanes.clipYV12(maskPlane, 0, 0, maskWidth, maskHeight);

        int keyColor = Rgb.rgb(0, 0, 0);
        int fontColor = Rgb.rgb(0, 255, 0);
        YuvBlit.blitYV12(maskPlanes, videoPlanes, keyColor, 0xa0, fontColor);
    }

    public void demoLoad() {
        String name = "src.jpg";
        String filepath = makePath(name);
        Bitmap bitmap = loadBitmap(filepath);
        if (bitmap != null) {
            byte[] yuv420sp = getYV12(bitmap);
            filepath = makePath("src.yuv");
            saveData(yuv420sp, filepath);
        }
    }

    public void demoYuv() {
        float textSize = 24.0f;
        Bitmap bitmap = textAsBitmap("好贵啊", textSize, Color.argb(255, 0, 255, 0));

        // dump bitmap
        {
            ByteBuffer buffer = ByteBuffer.allocate(bitmap.getWidth() * bitmap.getHeight() * 4);
            bitmap.copyPixelsToBuffer(buffer);
            String name = formatName(bitmap, "text", ".rgb32");
            String filepath = makePath(name);
            saveData(buffer.array(), filepath);
        }

        byte[] yuv420sp = getNV21(bitmap.getWidth(), bitmap.getHeight(), bitmap);
        String name = formatName(bitmap, "text", ".nv21");
        String filepath = makePath(name);
            saveData(yuv420sp, filepath);

        byte[] yv12Frame = getYV12(bitmap);
        name = formatName(bitmap, "text", ".yv12");
        filepath = makePath(name);
        saveData(yv12Frame, filepath);
    }

    public void demoBitmap() {
        float textSize = 24.0f;
        Bitmap bitmap = textAsBitmap("好贵啊", textSize, Color.argb(255, 0, 255, 0));
        String filepath = makePath("demo.jpg");

        try {
            saveBitmap(bitmap, filepath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public Bitmap textAsBitmap(String text, float textSize, int textColor) {
        Paint paint = new Paint();
        paint.setTextSize(textSize);
        paint.setColor(textColor);
        paint.setTextAlign(Paint.Align.LEFT);
        float baseline = -paint.ascent(); // ascent() is negative
        int width = (int) (paint.measureText(text) + 0.5f); // round
        int height = (int) (baseline + paint.descent() + 0.5f);
        Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(image);
        canvas.drawText(text, 0, baseline, paint);
        return image;
    }

    public void saveBitmap(Bitmap bitmap, String filepath) throws IOException {
        File file = new File(filepath);
        OutputStream os = new BufferedOutputStream(new FileOutputStream(file));
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
        os.close();
    }

    public void saveData(byte[] data, String filepath) {
        try {
            File file = new File(filepath);
            OutputStream os = new BufferedOutputStream(new FileOutputStream(file));
            os.write(data);
            os.close();
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    public String makePath(String name) {
        String filepath = Environment.getExternalStorageDirectory().getAbsolutePath();
        return filepath + "/Download/" + name;
    }

    public String formatName(Bitmap bitmap, String prefix, String ext) {
        return prefix + '_' + Integer.toString(bitmap.getWidth()) + '-' + Integer.toString(bitmap.getHeight()) + ext;
    }

    // untested function
    byte [] getNV21(int inputWidth, int inputHeight, Bitmap scaled) {

        int [] argb = new int[inputWidth * inputHeight];

        scaled.getPixels(argb, 0, inputWidth, 0, 0, inputWidth, inputHeight);

        byte [] yuv = new byte[inputWidth*inputHeight*3/2];
        encodeYUV420SP(yuv, argb, inputWidth, inputHeight);

        scaled.recycle();

        return yuv;
    }

    byte [] getYV12(Bitmap bitmap) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        byte [] yuv = new byte[width*height*3/2];
        ByteBuffer buffer = ByteBuffer.allocate(width* height* 4);
        bitmap.copyPixelsToBuffer(buffer);

        ColorConvert.rgb32ToYV12(buffer.array(), yuv, width, height);
        return yuv;
    }


    void encodeYUV420SP(byte[] yuv420sp, int[] argb, int width, int height) {
        final int frameSize = width * height;

        int yIndex = 0;
        int uvIndex = frameSize;

        int a, R, G, B, Y, U, V;
        int index = 0;
        for (int j = 0; j < height; j++) {
            for (int i = 0; i < width; i++) {

                a = (argb[index] & 0xff000000) >> 24; // a is not used obviously
                R = (argb[index] & 0xff0000) >> 16;
                G = (argb[index] & 0xff00) >> 8;
                B = (argb[index] & 0xff) >> 0;

                // well known RGB to YUV algorithm
                Y = ( (  66 * R + 129 * G +  25 * B + 128) >> 8) +  16;
                U = ( ( -38 * R -  74 * G + 112 * B + 128) >> 8) + 128;
                V = ( ( 112 * R -  94 * G -  18 * B + 128) >> 8) + 128;

                // NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2
                //    meaning for every 4 Y pixels there are 1 V and 1 U.  Note the sampling is every other
                //    pixel AND every other scanline.
                yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
                if (j % 2 == 0 && index % 2 == 0) {
                    yuv420sp[uvIndex++] = (byte)((U<0) ? 0 : ((U > 255) ? 255 : U));
                    yuv420sp[uvIndex++] = (byte)((V<0) ? 0 : ((V > 255) ? 255 : V));
                }

                index ++;
            }
        }
    }



    public Bitmap loadBitmap(String filepath) {
        return BitmapFactory.decodeFile(filepath);
    }


    private static final int PERMISSIONS_REQUEST_CODE_WRITE_STORAGE = 201;

    private void checkCameraPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_CODE_WRITE_STORAGE);
            } else {
                //
            }
        }
    }

}
